]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st: Only consider visible children for :first/:last-child
authorFlorian Müllner <fmuellner@gnome.org>
Tue, 27 Nov 2018 01:21:37 +0000 (02:21 +0100)
committerFlorian Müllner <florian.muellner@gmail.com>
Sat, 2 Mar 2019 12:19:40 +0000 (12:19 +0000)
While mapping the :first/:last-child pseudo classes directly to the
ClutterActor:first-child/:last-child properties allows for an easy
implementation, it is unexpected that rules can appear to not have
an effect because the selected child is hidden. GTK's behavior of
applying the classes to visible children makes much more sense, so
change our implementation to do the same.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/312

src/st/st-widget.c

index eea5f7f3ba8a479a666de6f2068ee9f49fcdda2d..f5ca8928aa9acbc32ea417074ec7292453ace29f 100644 (file)
@@ -80,11 +80,8 @@ struct _StWidgetPrivate
   ClutterActor *label_actor;
   gchar        *accessible_name;
 
-  /* Even though Clutter has first_child/last_child properties,
-   * we need to keep track of the old first/last children so
-   * that we can remove the pseudo classes on them. */
-  StWidget *prev_last_child;
-  StWidget *prev_first_child;
+  StWidget *last_visible_child;
+  StWidget *first_visible_child;
 
   StThemeNodePaintState paint_states[2];
   int current_paint_state : 2;
@@ -322,8 +319,8 @@ st_widget_dispose (GObject *gobject)
       priv->texture_file_changed_id = 0;
     }
 
-  g_clear_object (&priv->prev_first_child);
-  g_clear_object (&priv->prev_last_child);
+  g_clear_object (&priv->first_visible_child);
+  g_clear_object (&priv->last_visible_child);
 
   G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject);
 }
@@ -1488,6 +1485,64 @@ st_widget_get_resource_scale (StWidget *widget,
                                            resource_scale);
 }
 
+static void
+st_widget_set_first_visible_child (StWidget     *widget,
+                                   ClutterActor *actor)
+{
+  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
+
+  if (priv->first_visible_child == NULL && actor == NULL)
+    return;
+
+  if (priv->first_visible_child != NULL &&
+      CLUTTER_ACTOR (priv->first_visible_child) == actor)
+    return;
+
+  if (priv->first_visible_child != NULL)
+    {
+      st_widget_remove_style_pseudo_class (priv->first_visible_child, "first-child");
+      g_clear_object (&priv->first_visible_child);
+    }
+
+  if (actor == NULL)
+    return;
+
+  if (ST_IS_WIDGET (actor))
+    {
+      st_widget_add_style_pseudo_class (ST_WIDGET (actor), "first-child");
+      priv->first_visible_child = g_object_ref (ST_WIDGET (actor));
+    }
+}
+
+static void
+st_widget_set_last_visible_child (StWidget     *widget,
+                                  ClutterActor *actor)
+{
+  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
+
+  if (priv->last_visible_child == NULL && actor == NULL)
+    return;
+
+  if (priv->last_visible_child != NULL &&
+      CLUTTER_ACTOR (priv->last_visible_child) == actor)
+    return;
+
+  if (priv->last_visible_child != NULL)
+    {
+      st_widget_remove_style_pseudo_class (priv->last_visible_child, "last-child");
+      g_clear_object (&priv->last_visible_child);
+    }
+
+  if (actor == NULL)
+    return;
+
+  if (ST_IS_WIDGET (actor))
+    {
+      st_widget_add_style_pseudo_class (ST_WIDGET (actor), "last-child");
+      priv->last_visible_child = g_object_ref (ST_WIDGET (actor));
+    }
+}
+
 static void
 st_widget_name_notify (StWidget   *widget,
                        GParamSpec *pspec,
@@ -1529,56 +1584,89 @@ st_widget_reactive_notify (StWidget   *widget,
     st_widget_sync_hover(widget);
 }
 
+static ClutterActor *
+find_nearest_visible_backwards (ClutterActor *actor)
+{
+  ClutterActor *prev = actor;
+
+  while (prev != NULL && !clutter_actor_is_visible (prev))
+    prev = clutter_actor_get_previous_sibling (prev);
+  return prev;
+}
+
+static ClutterActor *
+find_nearest_visible_forward (ClutterActor *actor)
+{
+  ClutterActor *next = actor;
+
+  while (next != NULL && !clutter_actor_is_visible (next))
+    next = clutter_actor_get_next_sibling (next);
+  return next;
+}
+
 static void
-st_widget_first_child_notify (StWidget   *widget,
-                              GParamSpec *pspec,
-                              gpointer    data)
+st_widget_visible_notify (StWidget   *widget,
+                          GParamSpec *pspec,
+                          gpointer    data)
 {
-  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
-  ClutterActor *first_child;
+  ClutterActor *actor = CLUTTER_ACTOR (widget);
+  ClutterActor *parent = clutter_actor_get_parent (actor);
+
+  if (parent == NULL || !ST_IS_WIDGET (parent))
+    return;
 
-  if (priv->prev_first_child != NULL)
+  if (clutter_actor_is_visible (actor))
     {
-      st_widget_remove_style_pseudo_class (priv->prev_first_child, "first-child");
-      g_clear_object (&priv->prev_first_child);
+      ClutterActor *before, *after;
+
+      before = clutter_actor_get_previous_sibling (actor);
+      if (find_nearest_visible_backwards (before) == NULL)
+        st_widget_set_first_visible_child (ST_WIDGET (parent), actor);
+
+      after = clutter_actor_get_next_sibling (actor);
+      if (find_nearest_visible_forward (after) == NULL)
+        st_widget_set_last_visible_child (ST_WIDGET (parent), actor);
     }
+  else
+    {
+      if (st_widget_has_style_pseudo_class (widget, "first-child"))
+        {
+          ClutterActor *new_first;
 
-  first_child = clutter_actor_get_first_child (CLUTTER_ACTOR (widget));
+          new_first = find_nearest_visible_forward (CLUTTER_ACTOR (widget));
+          st_widget_set_first_visible_child (ST_WIDGET (parent), new_first);
+        }
 
-  if (first_child == NULL)
-    return;
+      if (st_widget_has_style_pseudo_class (widget, "last-child"))
+        {
+          ClutterActor *new_last;
 
-  if (ST_IS_WIDGET (first_child))
-    {
-      st_widget_add_style_pseudo_class (ST_WIDGET (first_child), "first-child");
-      priv->prev_first_child = g_object_ref (ST_WIDGET (first_child));
+          new_last = find_nearest_visible_backwards (CLUTTER_ACTOR (widget));
+          st_widget_set_last_visible_child (ST_WIDGET (parent), new_last);
+        }
     }
 }
 
+static void
+st_widget_first_child_notify (StWidget   *widget,
+                              GParamSpec *pspec,
+                              gpointer    data)
+{
+  ClutterActor *first_child;
+
+  first_child = clutter_actor_get_first_child (CLUTTER_ACTOR (widget));
+  st_widget_set_first_visible_child (widget, find_nearest_visible_forward (first_child));
+}
+
 static void
 st_widget_last_child_notify (StWidget   *widget,
                              GParamSpec *pspec,
                              gpointer    data)
 {
-  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
   ClutterActor *last_child;
 
-  if (priv->prev_last_child != NULL)
-    {
-      st_widget_remove_style_pseudo_class (priv->prev_last_child, "last-child");
-      g_clear_object (&priv->prev_last_child);
-    }
-
   last_child = clutter_actor_get_last_child (CLUTTER_ACTOR (widget));
-
-  if (last_child == NULL)
-    return;
-
-  if (ST_IS_WIDGET (last_child))
-    {
-      st_widget_add_style_pseudo_class (ST_WIDGET (last_child), "last-child");
-      priv->prev_last_child = g_object_ref (ST_WIDGET (last_child));
-    }
+  st_widget_set_last_visible_child (widget, find_nearest_visible_backwards (last_child));
 }
 
 static void
@@ -1596,6 +1684,7 @@ st_widget_init (StWidget *actor)
   g_signal_connect (actor, "notify::resource-scale", G_CALLBACK (st_widget_resource_scale_notify), NULL);
   g_signal_connect (actor, "notify::reactive", G_CALLBACK (st_widget_reactive_notify), NULL);
 
+  g_signal_connect (actor, "notify::visible", G_CALLBACK (st_widget_visible_notify), NULL);
   g_signal_connect (actor, "notify::first-child", G_CALLBACK (st_widget_first_child_notify), NULL);
   g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL);
   priv->texture_file_changed_id = g_signal_connect (st_texture_cache_get_default (), "texture-file-changed",